#include "init.h"
#include "helper.h"
#include "common.h"
#include "scaler.h"
#include "pushgateway_client.h"
// #include "skywalking_client.h"
#include "span.h"
#include "shm.h"
#include "segment.h"
#include "execute.h"
#include "agent.h"
#include "utils.h"

#include <string>
#include <unistd.h>
#include <thread>
#include <malloc.h>

#include "sys/mman.h"

extern PushGatewayClient *PushGatewayClient::instance;
// extern SkywalkingClient *SkywalkingClient::instance;

extern void (*ori_execute_ex)(zend_op_array *op_array TSRMLS_DC);
extern void (*ori_execute_internal)(zend_execute_data *execute_data, int return_value_used TSRMLS_DC);

long start_micro_time, end_micro_time;

void init_minit()
{
    // PushGatewayClient *pushgateway_client = PushGatewayClient::newInstance();
    // SkywalkingClient *skywalking_client = SkywalkingClient::newInstance();
    // skywalking_client->init();

    // 监控自定义类方法
    ori_execute_ex = zend_execute;
    zend_execute = monitorpro_execute_ex;

    // 监控内置类方法
    ori_execute_internal = zend_execute_internal;
    zend_execute_internal = monitorpro_execute_internal;
}

void init_mshutdown() {}

void init_rinit()
{
    // // 初始化 skywalking 相关数据
    // zval *headers = &MONITORPRO_G(curl_header);
    // array_init(headers);

    // std::string uri = server_param("REQUEST_URI");
    // std::string host = server_param("HTTP_HOST");
    // std::string port = server_param("SERVER_PORT");
    // std::string addr = server_param("SERVER_ADDR");
    // std::string peer = "";

    // if (host != "" && port != "")
    // {
    //     peer = host + ":" + port;
    // }
    // else if (addr != "" && port != "")
    // {
    //     peer = addr + ":" + port;
    // }

    // PushGatewayClient *pushgateway_client = PushGatewayClient::newInstance();
    // pushgateway_client->run();

    // SkywalkingClient *skywalking_client = SkywalkingClient::newInstance();
    // Segment *segment = skywalking_client->getSegment();
    // auto *span = segment->createSpan(SkySpanType::Entry, SkySpanLayer::Http, 8001);
    // span->setOperationName(uri);
    // span->setPeer(peer);
    // span->addTag("url", uri);
    // segment->createRefs();
    // skywalking_client->run();

    // 获取开始执行时间
    struct timeval tv;
    gettimeofday(&tv, NULL);
    start_micro_time = tv.tv_sec * 1000000 + tv.tv_usec;
}

void init_rshutdown()
{
    // SkywalkingClient *skywalking_client = SkywalkingClient::newInstance();
    // Segment *seg = skywalking_client->getSegment();
    // seg->setStatusCode(SG(sapi_headers).http_response_code);
    // std::string msg = seg->marshal();
    // skywalking_client->delSeg();
    // skywalking_client->push(msg);
    // if (!MONITORPRO_G(skyenable))
    // {
    //     skywalking_client->clean();
    // }

    // 获取结束执行时间
    struct timeval tv;
    gettimeofday(&tv, NULL);
    end_micro_time = tv.tv_sec * 1000000 + tv.tv_usec;
    long execute_micro_time = end_micro_time - start_micro_time;

    PushGatewayClient *pushgateway_client = PushGatewayClient::newInstance();

    std::string sapi = sapi_module.name;
    if (sapi == "fpm-fcgi")
    {
        std::string uri = server_param("REQUEST_URI");
        std::string host = server_param("HTTP_HOST");
        std::string port = server_param("SERVER_PORT");
        std::string addr = server_param("SERVER_ADDR");
        std::string method = server_param("REQUEST_METHOD");
        std::string peer = "";
        std::string path = "";

        int pos = uri.find("?");
        path = uri.substr(0, pos);
        logger(path);

        if (host != "" && port != "")
        {
            peer = host + ":" + port;
        }
        else if (addr != "" && port != "")
        {
            peer = addr + ":" + port;
        }

        int code = SG(sapi_headers).http_response_code;
        std::string http_code = std::to_string(code);

        Scaler *sc_total = new Scaler;
        sc_total->setIndex(INDEX_HTTP_SERVER_HANDLED_TOTAL);
        sc_total->addItem(ITEM_HTTP_CODE, http_code);
        sc_total->addItem(ITEM_HTTP_METHOD, method);
        sc_total->addItem(ITEM_HTTP_FULL_PATH, "");
        sc_total->addItem(ITEM_HTTP_PATH, path);
        sc_total->addItem(ITEM_HTTP_PEER, peer);
        sc_total->addItem(ITEM_CODE, "0");
        pushgateway_client->setCounter(sc_total);

        Scaler *sc_second = new Scaler;
        sc_second->setIndex(INDEX_HTTP_SERVER_HANDLING_SECCONDS);
        sc_second->addItem(ITEM_HTTP_METHOD, method);
        sc_second->addItem(ITEM_HTTP_FULL_PATH, "");
        sc_second->addItem(ITEM_HTTP_PATH, path);
        sc_second->addItem(ITEM_HTTP_PEER, peer);
        pushgateway_client->setBucket(sc_second, execute_micro_time * pow(0.1, MONITORPRO_HISTOGRAM_DECIAML));

        delete sc_total;
        delete sc_second;
        sc_total = nullptr;
        sc_second = nullptr;
        malloc_trim(0);
    }

    if (!MONITORPRO_G(pushenable))
    {
        pushgateway_client->clean();
    }

    pushgateway_client->run();

    // zval *headers = &MONITORPRO_G(curl_header);
    // zval_dtor(headers);
    // headers = nullptr;
    // malloc_trim(0);
}